package com.card.hwatt.assembler;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.log4j.Logger;

import com.card.hwatt.controllers.MonthWorkController;
import com.card.hwatt.dto.*;

/**
 * 月考勤
 * @author Administrator
 *
 */
public final class MonthWorkAssembler {

	private static Logger logger = Logger.getLogger(MonthWorkController.class);

	private static final String[] PARSE_PATTERNS = new String[] {
			"yyyy-M-d HHmm", "yyyy-MM-dd", "yyyy-MM-dd HHmmss",
			"yyyy-MM-dd HH:mm:ss", "yyyy-M-d HH:mm:ss" };

	// private static final String FORMAT_KEY = "%d-%d-%d ";
	// KEY_OK = "√"
	private static final String KEY_FIELD = "d", KEY_OK = "B", KEY_NIGHT = "Y",
			KEY_HOLIDAY = "休", KEY_FULL = "BY";

	public static MonthWork convert(Employee employee, List<CardRecord> cards,
			List<Leave> leaves, List<Holiday> holidaies, Schedule schedule) {

		MonthWork dto = new MonthWork();
		dto.id = employee.id;
		dto.departmentId = employee.departmentId;
		dto.departmentName = employee.departmentName;
		dto.name = employee.name;
		dto.employeeCode = employee.employeeCode;

		dto.days = 0;
		dto.day = 0;
		dto.night = 0;
		dto.leave = 0;
		dto.full = 0;
		dto.late = 0;
		dto.early = 0;
		dto.holiday = 0;

		Class<?> cls = dto.getClass();

		for (Holiday holiday : holidaies) {
			try {
				Field field = cls.getField(KEY_FIELD
						+ Integer.valueOf(holiday.id.substring(6)));
				field.set(dto, KEY_HOLIDAY);
			} catch (Exception e) {
				logger.error(e);
			}
		}

		for (Leave leave : leaves) {
			if (leave == null || leave.employeeId != employee.id) {
				continue;
			}
			try {
				Field field = cls.getField(KEY_FIELD
						+ Integer.valueOf(leave.name.substring(6)));
				field.set(dto, leave.key);
			} catch (Exception e) {
				logger.error(e);
			}
		}

		if (schedule != null) {
			for (CardRecord card : cards) {
				try {
					Calendar calendar = Calendar.getInstance();
					calendar.setTime(DateUtils.parseDate(card.date,
							PARSE_PATTERNS));
					int date = calendar.get(Calendar.DATE);

					Field field = cls.getField("d" + date);

					String[] keys = new String[3];

					// 白班
					setDay(card, calendar, schedule, keys, dto);

					// 夜班
					setNigth(card, calendar, schedule, keys, dto);

					if (StringUtils.isNotEmpty(keys[0])
							&& StringUtils.isNotEmpty(keys[1])
							&& StringUtils.isNotEmpty(keys[2])) {
						field.set(dto, KEY_FULL);
						dto.full++;
						dto.days += 2;
					} else if (StringUtils.isNotEmpty(keys[0])
							&& StringUtils.isNotEmpty(keys[1])
							&& StringUtils.isEmpty(keys[2])) {
						field.set(dto, KEY_OK);
						dto.day++;
						dto.days++;
					} else if (StringUtils.isEmpty(keys[0])
							&& StringUtils.isEmpty(keys[1])
							&& StringUtils.isNotEmpty(keys[2])) {
						field.set(dto, KEY_NIGHT);
						dto.night++;
						dto.days++;
					}
				} catch (Exception e) {
					logger.error(e);
				}
			}
		}

		return dto;
	}

	private static void setDay(CardRecord cardDay, Calendar calendar,
			Schedule schedule, String[] keys, MonthWork dto) {

		if (schedule.morningStartTime == null
				|| schedule.afternoonStartTime == null) {
			return;
		}

		if (cardDay.morningStart != null && cardDay.morningEnd != null
				&& cardDay.afternoonStart != null
				&& cardDay.afternoonEnd != null) {
			keys[0] = KEY_OK;
			keys[1] = KEY_OK;
			try {
				// 上午
				Calendar calendarMorningStart = Calendar.getInstance();
				calendarMorningStart.setTime(DateUtils.parseDate(
						calendar.get(Calendar.YEAR) + "-"
								+ (calendar.get(Calendar.MONTH) + 1) + "-"
								+ calendar.get(Calendar.DATE) + " "
								+ schedule.morningStartTime, PARSE_PATTERNS));
				Calendar calendarMorningEnd = Calendar.getInstance();
				calendarMorningEnd.setTime(calendarMorningStart.getTime());
				calendarMorningEnd.add(Calendar.SECOND,
						schedule.morningEndTime * 60);

				if (cardDay.morningStart.after(calendarMorningStart.getTime())) {
					dto.late++;
				}
				if (cardDay.morningEnd.before(calendarMorningEnd.getTime())) {
					dto.early++;
				}

				// 下午
				Calendar calendarAfternoonStart = Calendar.getInstance();
				calendarAfternoonStart.setTime(DateUtils.parseDate(
						calendar.get(Calendar.YEAR) + "-"
								+ (calendar.get(Calendar.MONTH) + 1) + "-"
								+ calendar.get(Calendar.DATE) + " "
								+ schedule.afternoonStartTime, PARSE_PATTERNS));
				Calendar calendarAfternoonEnd = Calendar.getInstance();
				calendarAfternoonEnd.setTime(calendarAfternoonStart.getTime());
				calendarAfternoonEnd.add(Calendar.SECOND,
						schedule.afternoonEndTime * 60);

				if (cardDay.afternoonStart.after(calendarAfternoonStart
						.getTime())) {
					dto.late++;
				}
				if (cardDay.nightStart == null
						&& cardDay.afternoonEnd.before(calendarAfternoonEnd
								.getTime())) {
					dto.early++;
				}
			} catch (Exception e) {
				logger.error(e);
			}
		}
	}

	private static void setNigth(CardRecord cardDay, Calendar calendar,
			Schedule schedule, String[] keys, MonthWork dto) {

		if (schedule.nightStartTime == null) {
			return;
		}
		if (cardDay.nightStart != null && cardDay.nightEnd != null) {

			// 巡检
			if (ArrayUtils.isEmpty(schedule.nightCheckList)) {
				keys[2] = KEY_NIGHT;
			} else {
				Class<?> cls = cardDay.getClass();
				for (int i = 1; i <= 4; i++) {
					try {
						Field f = cls.getField("n" + i);
						if (f.get(cardDay) == null) {
							break;
						}
					} catch (Exception e) {
						logger.error(e);
					}

					if (schedule.nightCheckList.length == i) {
						keys[2] = KEY_NIGHT;
						break;
					}
				}
			}

			if (keys[2] == KEY_NIGHT) {
				try {
					Calendar calendarStart = Calendar.getInstance();
					calendarStart.setTime(DateUtils.parseDate(
							calendar.get(Calendar.YEAR) + "-"
									+ (calendar.get(Calendar.MONTH) + 1) + "-"
									+ calendar.get(Calendar.DATE) + " "
									+ schedule.nightStartTime, PARSE_PATTERNS));
					Calendar calendarEnd = Calendar.getInstance();
					calendarEnd.setTime(calendarStart.getTime());
					calendarEnd
							.add(Calendar.SECOND, schedule.nightEndTime * 60);

					if (cardDay.afternoonEnd == null
							&& cardDay.nightStart
									.after(calendarStart.getTime())) {
						dto.late++;
					}
					if (cardDay.nightEnd.before(calendarEnd.getTime())) {
						dto.early++;
					}
				} catch (Exception e) {
					logger.error(e);
				}
			}
		}
	}

	public static Map<String, Object> convert(List<Employee> employees,
			List<CardRecord> cards, List<Leave> leaves,
			List<Holiday> holidaies, Schedule schedule) {

		Map<String, Object> result = new HashMap<String, Object>();

		List<Integer> holidayList = new ArrayList<Integer>();
		for (Holiday holiday : holidaies) {
			int day = Integer.valueOf(holiday.id.substring(6));
			holidayList.add(day);
		}
		result.put("holidaies", holidayList);

		Map<Employee, List<CardRecord>> map = new HashMap<Employee, List<CardRecord>>();
		for (Employee employee : employees) {
			List<CardRecord> employeeCards = new ArrayList<CardRecord>();
			List<CardRecord> skipList = new ArrayList<CardRecord>();
			for (CardRecord card : cards) {
				if (!employee.id.equals(card.employeeId)) {
					continue;
				}
				employeeCards.add(card);
				skipList.add(card);
			}
			for (CardRecord card : skipList) {
				cards.remove(card);
			}
			if (employeeCards.size() == 0) {
				continue;
			}
			map.put(employee, employeeCards);
		}

		List<MonthWork> rows = new ArrayList<MonthWork>();
		for (Entry<Employee, List<CardRecord>> item : map.entrySet()) {
			MonthWork monthWork = convert(item.getKey(), item.getValue(),
					leaves, holidaies, schedule);
			rows.add(monthWork);
		}

		result.put("total", rows.size());
		result.put("rows", rows);

		MonthWork footerDay = new MonthWork();
		footerDay.departmentName = "白班";
		footerDay.employeeCode = "：";

		MonthWork footerNight = new MonthWork();
		footerNight.departmentName = "夜班";
		footerNight.employeeCode = "：";

		MonthWork footerFull = new MonthWork();
		footerFull.departmentName = "白连夜";
		footerFull.employeeCode = "：";

		MonthWork footer = new MonthWork();
		footer.departmentName = "工日汇总";
		footer.employeeCode = "：";
		footer.days = 0;
		footer.day = 0;
		footer.night = 0;
		footer.full = 0;
		footer.leave = 0;
		footer.late = 0;
		footer.early = 0;
		footer.holiday = 0;

		Class<?> cls = MonthWork.class;
		for (int i = 1; i <= 31; i++) {
			try {
				Field field = cls.getField(KEY_FIELD + i);

				field.set(footerDay, "0");
				field.set(footerNight, "0");
				field.set(footerFull, "0");
				field.set(footer, "0");

				for (MonthWork row : rows) {
					if (KEY_OK.equals(field.get(row))) {
						int val = Integer.valueOf(field.get(footerDay)
								.toString());
						field.set(footerDay, String.valueOf(++val));

						val = Integer.valueOf(field.get(footer).toString());
						field.set(footer, String.valueOf(++val));
					} else if (KEY_NIGHT.equals(field.get(row))) {
						int val = Integer.valueOf(field.get(footerNight)
								.toString());
						field.set(footerNight, String.valueOf(++val));

						val = Integer.valueOf(field.get(footer).toString());
						field.set(footer, String.valueOf(++val));
					} else if (KEY_FULL.equals(field.get(row))) {
						int val = Integer.valueOf(field.get(footerFull)
								.toString());
						field.set(footerFull, String.valueOf(++val));

						val = Integer.valueOf(field.get(footer).toString());
						val += 2;
						field.set(footer, String.valueOf(val));
					} else if (KEY_HOLIDAY.equals(field.get(row))) {
						row.holiday++;
					} else if (field.get(row) != null
							&& StringUtils
									.isNotEmpty(field.get(row).toString())) {
						row.leave++;
					}
				}
			} catch (Exception e) {
			}
		}

		for (MonthWork monthWork : rows) {
			footer.days += monthWork.days;
			footer.day += monthWork.day;
			footer.night += monthWork.night;
			footer.full += monthWork.full;
			footer.leave += monthWork.leave;
			footer.late += monthWork.late;
			footer.early += monthWork.early;
			footer.holiday += monthWork.holiday;
		}
		result.put("footer", new MonthWork[] { footerDay, footerNight,
				footerFull, footer });
		return result;
	}
}
